`timescale 1ns/1ns
`default_nettype none

`define GetPwmBits(lsb, num) I_cfg_pwm_setting[lsb+num-1:lsb]

module pixel_display_mbi5353
    #(
    parameter   DW      = 6
    )
    (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // control
    input  wire         I_enable,
    // ext setting
    input  wire         I_ext_lock_output,
    input  wire         I_ext_black_screen,
    // config
    input  wire [7:0]   I_cfg_clock_low,     // 时钟低电平时钟数
    input  wire         I_enable_5353b,     // 芯片类型
    input  wire [7:0]   I_cfg_clock_cycle,   // 时钟整周期时钟数
    input  wire [7:0]   I_cfg_clock_phase,   // 时钟相位
    input  wire [4:0]   I_cfg_scan_max,      // 最大扫描id
    input  wire [4:0]   I_cfg_port_max,      // 最大端口id
    input  wire [7:0]   I_cfg_line_pos,      // 换行位置
    input  wire [31:0]  I_cfg_out_mask,      // 输出mask
    input  wire [511:0] I_cfg_pwm_setting,   // pwm芯片设置
    // frame id
    output wire         O_frame_req,
    input  wire [1:0]   I_frame_id,
    // display control
    input  wire         I_display_reset,       // 强制重新开始串移
    output wire         O_display_ready,       // 输出模块ready
    output wire         O_display_end,         // 输出模块显示完一帧
    input  wire [7:0]   I_display_gclk_low,    // gclk低电平时钟数
    input  wire [7:0]   I_display_gclk_cycle,  // gclk整周期时钟数
    input  wire [19:0]  I_display_gclk_extra,  // gclk额外周期数
    // read request
    output reg          O_read_req,         // 读请求
    input  wire         I_read_busy,        // 读忙碌
    output wire [1:0]   O_read_buf_sel,     // 读取SDRAM分块地址
    output reg  [4:0]   O_read_scan_id,     // 读取的scan id
    output wire [4:0]   O_read_port_max,    // 读取的最大port id
    output reg  [5:0]   O_read_pin_id,      // 读取的芯片管脚id，0 - 15
    output wire [4:0]   O_read_chip_max,    // 读取的最大芯片id
    output wire [8:0]   O_read_ram_addr,    // 存放到RAM的起始地址
    output wire         O_read_buf_index,   // 读ram_sel
    // display buf
    output wire         O_ram_rden,
    output wire  [11:0] O_ram_raddr,
    input  wire [DW-1:0] I_ram_rdata,
    // scan output
    output wire         O_scan_prep,
    output wire         O_scan_commit,
    output wire [4:0]   O_scan_num,
    // led signal
    output wire         O_oe_out,
    output wire         O_load_out,
    output wire         O_clock_out,
    output wire [DW-1:0] O_data_out,
    input  wire         I_time_1ms_sync
     );

//------------------------Parameter----------------------
// delay
localparam  L = 3;  // 读ram延时=4

// fsm
localparam [4:0]
    IDLE    = 0,
    VSYNC0  = 1,
    VSYNC1  = 2,
    PREACT0 = 3,
    PREACT1 = 4,
    CONFIG0 = 5,
    CONFIG1 = 6,
    PREP    = 7,
    DATA0   = 8,
    NOP0    = 9,
    NOP1    = 10,
    DATA1   = 11,
    LOOP    = 12,
    WAIT    = 13,
    OPEN_DETECT0 = 14,
    OPEN_DETECT1 = 15,
    SHORT_DETECT0 = 16,
    SHORT_DETECT1 = 17;


//------------------------Local signal-------------------
// fsm
reg  [4:0]  state;
reg  [4:0]  next;
reg  [2:0]  config_cnt;

// pwm setting
wire [15:0] cfg_init_delay;    // gclk初始延时
wire [15:0] cfg_line_delay;    // gclk换行延时
wire [6:0]  cfg_gclk_group;    // gclk组数
wire [10:0] cfg_gclk_num;      // 子周期gclk数
wire [5:0]  cfg_chip_num;      // 串移链中芯片数量
wire [15:0] cfg_port0_reg1;    // port0寄存器1的值
wire [15:0] cfg_port0_reg2;    // port0寄存器2的值
wire [15:0] cfg_port0_reg3;    // port0寄存器3的值
wire [15:0] cfg_port1_reg1;    // port1寄存器1的值
wire [15:0] cfg_port1_reg2;    // port1寄存器2的值
wire [15:0] cfg_port1_reg3;    // port1寄存器3的值
wire [15:0] cfg_port2_reg1;    // port2寄存器1的值
wire [15:0] cfg_port2_reg2;    // port2寄存器2的值
wire [15:0] cfg_port2_reg3;    // port2寄存器3的值
wire [15:0] cfg_port3_reg1;    // 通用寄存器1的值 
wire [15:0] cfg_port3_reg2;    // 通用寄存器2的值
wire [15:0] cfg_port3_reg3;    // 通用寄存器3的值


wire [7:0]  cfg_last_high;     // 消影GCLK高电平宽度

// shift request
reg         shift_req;       // 串移开始
wire        shift_busy;      // 正在串移
reg  [9:0]  shift_bit_num;   // 串移长度(bit)
reg  [4:0]  shift_load_num;  // load宽度
reg  [DW-1:0] shift_data;      // 串移数据
wire        shift_data_ack;  // 数据确认
reg  [47:0] port_reg;
reg         read_over;
reg         shift_over;

// gclk output
wire        gclk_reset;
wire        gclk_start;
wire [5:0]  cfg_scan_num;
wire        row_start;
wire        row_end;
wire [5:0]  row_num;
wire        frame_end;

// read request
reg         read_ram_sel;

// scan output
reg         scan_prep;
reg         scan_commit;
reg  [4:0]  scan_num;
reg  [7:0]  pos_cnt;

// led signal
wire        oe_out;
wire        load_out;
wire        clock_out;
wire [DW-1:0] data_out;

// open detect
wire        detect_start;
wire        detect_done;
wire        od_scan_prep;
wire        od_scan_commit;
wire [4:0]  od_scan_num;
wire        od_shift_req;
wire [9:0]  od_shift_bit_num;
wire [4:0]  od_shift_load_num;
wire [DW-1:0] od_shift_data;
wire        od_gclk_out;

// display buf
reg  [L:0]  ram_rden_sr;

// misc
reg         display_ready;
reg  [DW-1:0] data_mask;


reg [5:0] watchdog_time_counter;
reg       watchdog_flag;

reg [11:0] O_ram_raddr_o;
reg [11:0] O_ram_raddr_1;              //R 地址缓存
reg [11:0] O_ram_raddr_2;              //G 地址缓存
reg [11:0] O_ram_raddr_3;              //B 地址缓存
reg [1:0]  cnt_3;                      // cnt_3：确定读RGB中的哪色，R:0,G:1,B:2
reg        cnt_2;                      // cnt_2：确定RGB中读高8位还是读低8位  高八位：1   低八位：0
reg [2:0]  cnt_8;                      // cnt_8：高或低8位位数计算

//------------------------Instantiation------------------
// data_shift_mbi5353
data_shift_mbi5353 /*{{{*/
    #(
    .DW                (DW      )
    )
  ds (
    .I_sclk            ( I_sclk ),
    .I_rst_n           ( I_rst_n ),
    .I_cfg_clock_low   ( I_cfg_clock_low ),
    .I_cfg_clock_cycle ( I_cfg_clock_cycle ),
    .I_cfg_clock_phase ( I_cfg_clock_phase ),
    .I_enable_5353b    ( I_enable_5353b   ),
    .I_shift_req       ( shift_req ),
    .O_shift_busy      ( shift_busy ),
    .I_shift_bit_num   ( shift_bit_num ),
    .I_shift_load_num  ( shift_load_num ),
    .I_shift_data      ( shift_data ),
    .O_shift_data_ack  ( shift_data_ack ),
    .O_load_out        ( load_out ),
    .O_clock_out       ( clock_out ),
    .O_data_out        ( data_out )
);/*}}}*/

// gclk_gen_mbi5353
gclk_gen_mbi5353 gg (/*{{{*/
    .I_sclk           ( I_sclk ),
    .I_rst_n          ( I_rst_n ),
    .I_cfg_gclk_low   ( I_display_gclk_low ),
    .I_cfg_gclk_cycle ( I_display_gclk_cycle ),
    .I_cfg_gclk_extra ( I_display_gclk_extra ),
    .I_cfg_last_high  ( cfg_last_high ),
    .I_gclk_reset     ( gclk_reset ),
    .I_gclk_start     ( gclk_start ),
    .I_init_delay     ( cfg_init_delay ),
    .I_scan_num       ( cfg_scan_num),
    .I_group_num      ( cfg_gclk_group),
    .I_gclk_num       ( cfg_gclk_num ),
    .I_line_delay     ( cfg_line_delay ),
    .O_gclk_out       ( oe_out ),
    .O_row_start      ( row_start ),
    .O_row_end        ( row_end ),
    .O_row_num        ( row_num ),
    .O_frame_end      ( frame_end )
);/*}}}*/

// open_detect_mbi5353
open_detect_mbi5353 /*{{{*/
    #(
    .DW                (DW      )
    )
  od (
    .I_sclk            ( I_sclk ),
    .I_rst_n           ( I_rst_n ),
    .I_enable          ( I_enable ),
    .I_detect_start    ( detect_start ),
    .O_detect_done     ( detect_done ),
    .I_cfg_scan_max    ( I_cfg_scan_max ),
    .I_cfg_pwm_setting ( I_cfg_pwm_setting ),
    .O_scan_prep       ( od_scan_prep ),
    .O_scan_commit     ( od_scan_commit ),
    .O_scan_num        ( od_scan_num ),
    .O_shift_req       ( od_shift_req ),
    .I_shift_busy      ( shift_busy ),
    .O_shift_bit_num   ( od_shift_bit_num ),
    .O_shift_load_num  ( od_shift_load_num ),
    .O_shift_data      ( od_shift_data ),
    .I_shift_data_ack  ( shift_data_ack ),
    .O_gclk_out        ( od_gclk_out )
);/*}}}*/

//------------------------Body---------------------------
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
// state
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        state <= IDLE;
    else if (!I_enable || I_display_reset)
        state <= IDLE;
    else
        state <= next;
end

// next
always @(*) begin
    case (state)
        IDLE: begin
            if (!display_ready && cfg_port3_reg2[5])    //通用寄存器，检测到开路侦测，启动侦测
                next = OPEN_DETECT0;
            else if (!display_ready && cfg_port3_reg2[15])  //通用寄存器，检测到短路侦测，启动侦测
                next =SHORT_DETECT0;
            else 
                    next = VSYNC0;
        end

        OPEN_DETECT0: begin
            next = OPEN_DETECT1;
        end

        OPEN_DETECT1: begin
            if (detect_done) begin
                if (!display_ready && (cfg_port3_reg2[15])) 
                 next =SHORT_DETECT0;
              else
                next = VSYNC0;
            end
            else
                next = OPEN_DETECT1;
        end

          SHORT_DETECT0: begin
                next = SHORT_DETECT1;
          end

        SHORT_DETECT1: begin
            if (detect_done)
                next = VSYNC0;
            else
                next = SHORT_DETECT1;
        end


        VSYNC0: begin
            next = VSYNC1;
        end

        VSYNC1: begin
            if (shift_req || shift_busy)
                next = VSYNC1;
            else
                next = PREACT0;
        end

        PREACT0: begin
            next = PREACT1;
        end

        PREACT1: begin
            if (shift_req || shift_busy)
                next = PREACT1;
            else
                next = CONFIG0;
        end

        CONFIG0: begin
            next = CONFIG1;
        end

        CONFIG1: begin
            if (shift_req || shift_busy)
                next = CONFIG1;
            else
                next = PREP;
        end

        PREP: begin                         //开始读SDRAM中图像数据
            if (I_read_busy)                //2个SDRAM时钟 此为125M 见cxy_pixel_reader
                next = PREP;
            else
                next = DATA0;
        end

        DATA0: begin
            next = NOP0;
        end

        NOP0: begin       
            next = NOP1;
        end

        NOP1: begin                         //此状态主要设置一扫图像数据的个数：48*芯片个数（N）*芯片引脚个数或组数（16）
            next = DATA1;
        end

        DATA1: begin                        //一扫图像数据发送，如完成跳至状态LOOP，判断一帧数据是否传送完
            if (shift_req || shift_busy)   
                next = DATA1;
            else
                next = LOOP;
        end

        LOOP: begin                          //计算是否完成一帧图像数据的传送（扫描数和芯片引脚相关） 如果完成就停止传送，等待显示一帧完成 
            if (shift_over)                  //如未传送完，跳转至PREP状态，开始下一扫数据的传送。
                next = WAIT;
            else
                next = PREP;
        end

        WAIT: begin
            if (frame_end ||  watchdog_flag)                     //数据传送完，如显示信号显示完（gclk_gen生成），则开始下一帧数据的传送，并开始此帧的显示。
                next = VSYNC0;
            else
                next = WAIT;
        end

        default: begin
            next = IDLE;
        end
    endcase
end
//--------------watch dog-----------------------



always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        watchdog_time_counter <= 6'd0;
      else if (!I_enable)
          watchdog_time_counter <= 6'd0;
      else if (state == VSYNC0) 
         watchdog_time_counter <= 6'd0;
      else if (I_time_1ms_sync) 
          watchdog_time_counter <= watchdog_time_counter+1'b1;
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        watchdog_flag <= 1'b0;
      else if (!I_enable)
          watchdog_flag <= 1'b0;
      else if (state == VSYNC0) 
         watchdog_flag <= 1'b0;
      else if (watchdog_time_counter ==6'd33 && I_time_1ms_sync)
         watchdog_flag <= 1'b1;
      else 
          watchdog_flag <= 1'b0;
end

// config_cnt: 0:通用 1:R 2:G 3:B  开路侦测时 config_cnt计算周期为3'd4才置为0
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        config_cnt <= 1'b0;
    else if (state == IDLE)
        config_cnt <= 1'b0;
    else if (state == CONFIG0) begin
        if (config_cnt == 3'd3)
            config_cnt <= 1'b0;
        else
            config_cnt <= config_cnt + 1'b1;
    end
end





//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++pwm setting++++++++++++++++++++
assign cfg_init_delay    = `GetPwmBits(0, 16);     //8'h00 ,8'h01    
assign cfg_line_delay    = `GetPwmBits(16, 16);    //8'h02 ,8'h03
assign cfg_gclk_group    = `GetPwmBits(32, 7);     //8'h04         gclk组数
assign cfg_gclk_num      = `GetPwmBits(40, 11);    //8'h05 ,8'h06  子周期gclk数
assign cfg_chip_num      = `GetPwmBits(56, 6);     //8'h07 
assign cfg_port0_reg1    = `GetPwmBits(64, 16);    //8'h08 ,8'h09  寄存器  R1
assign cfg_port0_reg2    = `GetPwmBits(80, 16);    //8'h0a ,8'h0b  寄存器  R2
assign cfg_port0_reg3    = `GetPwmBits(96, 16);    //8'h0c ,8'h0d  寄存器  R3
assign cfg_port1_reg1    = `GetPwmBits(112, 16);   //8'h0e ,8'h0f  寄存器  G1
assign cfg_port1_reg2    = `GetPwmBits(128, 16);   //8'h10 ,8'h11  寄存器  G2
assign cfg_port1_reg3    = `GetPwmBits(144, 16);   //8'h12 ,8'h13  寄存器  G3
assign cfg_port2_reg1    = `GetPwmBits(160, 16);   //8'h14 ,8'h15  寄存器  B1
assign cfg_port2_reg2    = `GetPwmBits(176, 16);   //8'h16 ,8'h17  寄存器  B2
assign cfg_port2_reg3    = `GetPwmBits(192, 16);   //8'h18 ,8'h19  寄存器  B3
assign cfg_port3_reg1    = `GetPwmBits(216, 16);   //8'h1b ,8'h1c  寄存器：通用1
assign cfg_port3_reg2    = `GetPwmBits(232, 16);   //8'h1d ,8'h1e  寄存器：通用2
assign cfg_port3_reg3    = `GetPwmBits(248, 16);   //8'h1f ,8'h20  寄存器：通用3
assign cfg_last_high     = `GetPwmBits(208, 8);    //8'h1a
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++frame id+++++++++++++++++++++++
assign O_frame_req = (state == VSYNC0) && !I_ext_lock_output;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++read request+++++++++++++++++++
assign O_read_port_max = (!I_enable)? 1'b0 : I_cfg_port_max;
assign O_read_ram_addr = (!I_enable)? 1'b0 : {read_ram_sel, 8'd0};
assign O_read_buf_sel  = (!I_enable)? 1'b0 : I_frame_id;
assign O_read_chip_max = (!I_enable)? 1'b0 : cfg_chip_num[4:0] - 1'b1;
assign O_read_buf_index= read_ram_sel;
// O_read_req
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        O_read_req <= 1'b0;
    else if (!I_enable)
        O_read_req <= 1'b0;
    else if (state == VSYNC0)
        O_read_req <= 1'b1;
    else if (state == DATA0 && !read_over)
        O_read_req <= 1'b1;
    else
        O_read_req <= 1'b0;
end

// O_read_scan_id
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        O_read_scan_id <= 1'b0;
    else if (!I_enable)
        O_read_scan_id <= 1'b0;
    else if (state == VSYNC0)
        O_read_scan_id <= 1'b0;
    else if (O_read_req && O_read_pin_id == 4'd15)
        O_read_scan_id <= O_read_scan_id + 1'b1;
end

// O_read_pin_id
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        O_read_pin_id <= 1'b0;
    else if (!I_enable)
        O_read_pin_id <= 1'b0;
    else if (state == VSYNC0)
        O_read_pin_id <= 1'b0;
    else if (O_read_req)begin
        if(O_read_pin_id == 'd15)
            O_read_pin_id <= 'd0;
        else 
            O_read_pin_id <= O_read_pin_id + 1'b1;
    end
end

// read_ram_sel
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        read_ram_sel <= 1'b0;
    else if (O_read_req)
        read_ram_sel <= !read_ram_sel;
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++display buf++++++++++++++++++++
assign O_ram_rden = (state == DATA0) || (state == DATA1 && shift_data_ack);
assign O_ram_raddr = O_ram_raddr_o;


//选RGB数据
// always @(*)begin                     
    // case (cnt_3)
           // 0: O_ram_raddr_o <= O_ram_raddr_1;
           // 1: O_ram_raddr_o <= O_ram_raddr_2;
    // default: O_ram_raddr_o <= O_ram_raddr_3;
    // endcase
// end 

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_ram_raddr_o <=  12'd0; 
    else if (!I_enable)
        O_ram_raddr_o <=  12'd0; 
    else if (state == PREP)
        O_ram_raddr_o <= {~read_ram_sel, 11'd0};//初始值从高位开始    
    else if (O_ram_rden)
        O_ram_raddr_o <= O_ram_raddr_o + 1;
end

//O_ram_raddr_1; //R 地址缓存

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_ram_raddr_1 <=  12'd0; 
    else if (!I_enable)
        O_ram_raddr_1 <=  12'd0; 
    else if (state == PREP)
        O_ram_raddr_1 <= {~read_ram_sel, 11'd32};                           //初始值从高位开始
     else if ( O_ram_rden && cnt_3 ==0 && cnt_8 ==7) begin  
          if      (cnt_2 == 1'b1)  O_ram_raddr_1 <= O_ram_raddr_1 -32-7;      //读高8位数据完成，地址跳转读低8位数据
         else if (cnt_2 == 1'b0)  O_ram_raddr_1 <= O_ram_raddr_1 +96-7;      //读低8位数据完成，调转第二个像素数据
     end     
    else if (O_ram_rden && cnt_3 == 2'd0)                                 //读8位数据地址
        O_ram_raddr_1 <= O_ram_raddr_1 + 1;
end


//O_ram_raddr_2; //G 地址缓存

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_ram_raddr_2 <=   12'd0; 
    else if (!I_enable)
        O_ram_raddr_2 <=   12'd0; 
    else if (state == PREP)
        O_ram_raddr_2 <=  {~read_ram_sel, 11'd40};                           //初始值从高位开始            
     else if ( O_ram_rden &&  cnt_3 == 1 && cnt_8 == 7) begin  
          if      (cnt_2 == 1'b1)  O_ram_raddr_2 <= O_ram_raddr_2 -32-7;      //读高8位数据完成，地址跳转读低8位数据
         else if (cnt_2 == 1'b0)  O_ram_raddr_2 <= O_ram_raddr_2 +96-7;      //读低8位数据完成，调转第二个像素数据
     end     
    else if (O_ram_rden && cnt_3 == 2'd1)
        O_ram_raddr_2 <= O_ram_raddr_2 + 1;
end

//O_ram_raddr_1; //B 地址缓存

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        O_ram_raddr_3 <=  12'd0;
    else if (!I_enable)
        O_ram_raddr_3 <=  12'd0;
    else if (state == PREP)
        O_ram_raddr_3 <= {~read_ram_sel, 11'd48};                           //初始值从高位开始      
     else if ( O_ram_rden &&  cnt_3 == 2 && cnt_8 == 7) begin  
          if      (cnt_2 == 1'b1)  O_ram_raddr_3 <= O_ram_raddr_3 -32-7;      //读高8位数据完成，地址跳转读低8位数据
         else if (cnt_2 == 1'b0)  O_ram_raddr_3 <= O_ram_raddr_3 +96-7;      //读低8位数据完成，调转第二个像素数据
     end     
    else if (O_ram_rden && cnt_3 == 2'd2)
        O_ram_raddr_3 <= O_ram_raddr_3 + 1;
end


//cnt_2 
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cnt_2 <= 1'b0;
    else if (!I_enable)
        cnt_2 <= 1'b1;    
    else if (state == PREP)
        cnt_2 <= 1'b1;                      //先读高位，再读低位
     else if (O_ram_rden && cnt_8 == 7)  //每读8位 其cnt_2 得翻转去读另外8位   
          cnt_2 <= cnt_2+1;         
end


//cnt_3[1:0]
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cnt_3 <= 2'd0;
    else if (!I_enable)
        cnt_3 <= 2'd0;
    else if (state == PREP)
       cnt_3 <= 2'd0;
     else if (O_ram_rden && cnt_8 == 7 && cnt_2 == 0)
            if(cnt_3 == 2)
                cnt_3 <= 2'd0;
            else 
                cnt_3 <= cnt_3 + 1'b1;
end


//cnt_8[2:0]
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        cnt_8 <= 3'd0;
    else if (!I_enable)
        cnt_8 <= 3'd0;
    else if (state == PREP)
       cnt_8 <= 3'd0;
     else if (O_ram_rden)
            if(cnt_8 == 7)
                cnt_8 <=3'd0;
            else 
                cnt_8 <= cnt_8 + 1'b1;
end


// ram_rden_sr
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        ram_rden_sr <= 1'b0;
    else
        ram_rden_sr <= {ram_rden_sr[L-1:0], O_ram_rden};  //O_ram_rden延时L个周期，？
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++shift request++++++++++++++++++
// shift_req
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_req <= 1'b0;
    else
    case(state)
        OPEN_DETECT1:  shift_req <= od_shift_req;
      SHORT_DETECT1: shift_req <= od_shift_req;
        VSYNC0,
        PREACT0,
        CONFIG0,
        NOP1:          shift_req <= 1'b1;

        default:       shift_req <= 1'b0;
    endcase
end

// shift_bit_num
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_bit_num <= 1'b0;
    else
    case(state)
        OPEN_DETECT1:  shift_bit_num <= od_shift_bit_num;
          SHORT_DETECT1: shift_bit_num <= od_shift_bit_num;
        VSYNC0,
        PREACT0:       shift_bit_num <= 10'd16;

        CONFIG0:          shift_bit_num <= 3*{cfg_chip_num, 4'd0};
        NOP1:          shift_bit_num <= 3*{cfg_chip_num, 4'd0};
    endcase
end

// shift_load_num
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_load_num <= 1'b0;
    else
    case(state)
        OPEN_DETECT1:  shift_load_num <= od_shift_load_num;
        SHORT_DETECT1: shift_load_num <= od_shift_load_num;
        VSYNC0:        shift_load_num <= 5'd2;
        PREACT0:       shift_load_num <= 5'd14;

        CONFIG0:
            case(config_cnt)
                0:      shift_load_num <= 5'd4;
                1:      shift_load_num <= 5'd4;
                2:      shift_load_num <= 5'd4;
                3:      shift_load_num <= 5'd4;
                default:shift_load_num <= 5'd16;
            endcase

        NOP1:       shift_load_num <= 5'd1;
    endcase
end

always @(posedge I_sclk or negedge I_rst_n) begin
     if (~I_rst_n)
          shift_data <= 1'b0;
     else
     case(state)
          OPEN_DETECT1:  shift_data <= od_shift_data;
          SHORT_DETECT1: shift_data <= od_shift_data;
          CONFIG1:       shift_data <= {DW{port_reg[47]}};

          DATA1:
                 if(I_ext_black_screen)
                      shift_data <= 1'b0;
                 else if(ram_rden_sr[L])
                      shift_data <= I_ram_rdata & data_mask;
     endcase
end

//port_reg  寄存器配置
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        port_reg <= 1'b0;
    else if(state == CONFIG0) begin
        case(config_cnt) 
            3'd0: port_reg <= {2'b00,cfg_port3_reg1[13:0],cfg_port3_reg2,cfg_port3_reg3}; //通用寄存器配置
            // 3'd1: port_reg <= {2'b01,cfg_port0_reg1[13:0],cfg_port0_reg2,cfg_port0_reg3}; // R  寄存器配置
            // 3'd2: port_reg <= {2'b10,cfg_port1_reg1[13:0],cfg_port1_reg2,cfg_port1_reg3}; // G  寄存器配置
            // 3'd3: port_reg <= {2'b11,cfg_port2_reg1[13:0],cfg_port2_reg2,cfg_port2_reg3}; // B  寄存器配置
        // default:port_reg <= 1'b0;
        default:port_reg <= {2'b01,cfg_port0_reg1[13:0],cfg_port0_reg2,cfg_port0_reg3}; // R  寄存器配置
        endcase 
    end
   else if (shift_data_ack)
         port_reg <= {port_reg[46:0], port_reg[47]};
end


// read_over
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        read_over <= 1'b0;
    else if (state == VSYNC0)
        read_over <= 1'b0;
    else if (O_read_req && O_read_scan_id == I_cfg_scan_max && O_read_pin_id == 4'd15)
        read_over <= 1'b1;
end

// shift_over
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        shift_over <= 1'b0;
    else
    case(state)
        VSYNC0: shift_over <= 1'b0;
        LOOP:   shift_over <= read_over;
    endcase
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++gclk output++++++++++++++++++++
assign gclk_reset   = (state == IDLE);
assign gclk_start   = (state == VSYNC0);
assign cfg_scan_num = I_cfg_scan_max + 1'b1;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++scan output++++++++++++++++++++
assign O_scan_prep   = scan_prep;
assign O_scan_num    = scan_num;
assign O_scan_commit = scan_commit;

// pos_cnt
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        pos_cnt <= 1'b0;
    else if (!I_enable)
        pos_cnt <= 1'b0;
    else if (row_end)
        pos_cnt <= 1'b1;
    else if (pos_cnt != 1'b0)
        pos_cnt <= pos_cnt + 1'b1;
end

// scan_prep
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_prep <= 1'b0;
    else if (!I_enable)
        scan_prep <= 1'b0;
    else if (state == OPEN_DETECT1)
        scan_prep <= od_scan_prep;
    else if (state == SHORT_DETECT1)
        scan_prep <= od_scan_prep;
    else
        scan_prep <= row_start;
end

// scan_commit
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_commit <= 1'b0;
    else if (!I_enable)
        scan_commit <= 1'b0;
    else if (state == OPEN_DETECT1)
        scan_commit <= od_scan_commit;
    else if (state == SHORT_DETECT1)
        scan_commit <= od_scan_commit;   
    else if (I_cfg_line_pos == 1'b0)
        scan_commit <= row_end;
    else if (pos_cnt == I_cfg_line_pos)
        scan_commit <= 1'b1;
    else
        scan_commit <= 1'b0;
end

// scan_num
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        scan_num <= 1'b0;
    else if (!I_enable)
        scan_num <= 1'b0;
    else if (state == OPEN_DETECT1)
        scan_num <= od_scan_num;
    else if (state == SHORT_DETECT1)
       scan_num <= od_scan_num;   
    else if (row_num == cfg_scan_num)
        scan_num <= 1'b0;
    else
        scan_num <= row_num[4:0];
end
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++led signal+++++++++++++++++++++
assign O_oe_out    = (!I_enable)? 1'b0
                   : (state == OPEN_DETECT1 || state == SHORT_DETECT1)? od_gclk_out
                   : oe_out;
assign O_load_out  = (!I_enable)? 1'b0 : load_out;
assign O_clock_out = (!I_enable)? 1'b0 : clock_out;
assign O_data_out  = (!I_enable)? 1'b0 : data_out;
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++open detect++++++++++++++++++++
assign detect_start = (state == OPEN_DETECT0 || state == SHORT_DETECT0);
//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

//{{{+++++++++++++++++++++misc+++++++++++++++++++++++++++
assign O_display_ready = display_ready;
assign O_display_end   = (state == WAIT) && frame_end;

// display_ready
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        display_ready <= 1'b0;
    else if (!I_enable)
        display_ready <= 1'b0;
    else if (state == VSYNC0)
        display_ready <= 1'b1;
end

// data_mask
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        data_mask <= {DW{1'b1}};
    else if (state == VSYNC0)
        data_mask <= {DW{1'b1}};
    else if (state == LOOP && O_read_scan_id == I_cfg_scan_max && O_read_pin_id == 4'd1)
        data_mask <= ~{
            {3{I_cfg_out_mask[31]}},
            {3{I_cfg_out_mask[30]}},
            {3{I_cfg_out_mask[29]}},
            {3{I_cfg_out_mask[28]}},
            {3{I_cfg_out_mask[27]}},
            {3{I_cfg_out_mask[26]}},
            {3{I_cfg_out_mask[25]}},
            {3{I_cfg_out_mask[24]}},
            {3{I_cfg_out_mask[23]}},
            {3{I_cfg_out_mask[22]}},
            {3{I_cfg_out_mask[21]}},
            {3{I_cfg_out_mask[20]}},
            {3{I_cfg_out_mask[19]}},
            {3{I_cfg_out_mask[18]}},
            {3{I_cfg_out_mask[17]}},
            {3{I_cfg_out_mask[16]}},
            {3{I_cfg_out_mask[15]}},
            {3{I_cfg_out_mask[14]}},
            {3{I_cfg_out_mask[13]}},
            {3{I_cfg_out_mask[12]}},
            {3{I_cfg_out_mask[11]}},
            {3{I_cfg_out_mask[10]}},
            {3{I_cfg_out_mask[9 ]}},
            {3{I_cfg_out_mask[8 ]}},
            {3{I_cfg_out_mask[7 ]}},
            {3{I_cfg_out_mask[6 ]}},
            {3{I_cfg_out_mask[5 ]}},
            {3{I_cfg_out_mask[4 ]}},
            {3{I_cfg_out_mask[3 ]}},
            {3{I_cfg_out_mask[2 ]}},
            {3{I_cfg_out_mask[1 ]}},
            {3{I_cfg_out_mask[0 ]}}
        };
end

//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
